home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
asm_0_m.arj
/
KBXDUAL.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-09-17
|
32KB
|
645 lines
; revised by rwt for dual-display systems, tests display type each time
; the window is activated. Done through calls to set-display-type, which
; is a re-written portion of the initialization routine. Also eliminated
; possibility of entering ASCII 127 (in SCR_TABLE).
;
; All changes to the program are in UPPER-case letters. Un-commented
; portions are closely related to the original, commented out but
; commented, source code. This should work with any normal two display
; system, e.g. mono with either cga or ega.
;
;KBX.COM for the IBM Personal Computer - 1987 by Jeff Prosise
;
kb_data equ 60h ;keyboard data port
kb_ctrl equ 61h ;keyboard control port
eoi equ 20h ;8259 EOI value
int_ctrl equ 20h ;8259 port address
;
bios_data segment at 40h ;BIOS data area
org 17h
kb_status db ? ;keyboard status byte
org 1Ah
buffer_head dw ? ;pointer to keyboard buffer head
buffer_tail dw ? ;pointer to keyboard buffer tail
org 80h
buffer_start dw ? ;starting keyboard buffer address
buffer_end dw ? ;ending keyboard buffer address
bios_data ends
;
code segment para public 'code' ;code segment
assume cs:code
org 100h
begin: jmp initialize ;goto initialization code
;
copyright db 'Copyright 1987 Ziff-Davis Publishing Co.',1Ah
enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
screen_buffer dw offset initialize ;pointer to screen buffer
aux_shift db 0 ;auxiliary keyboard status byte
old_shift db 0 ;storage for shift status
window_status db 0 ;window display status
adapter db 2 ;0 = MDA, 1 = CGA, 2 = EGA
video_segment dw 0B800h ;default video segment
border_attr db 2Fh ;window border attribute
text_attr db 1Bh ;window border attribute
cursor_mode dw 0607h ;default cursor shape
cursor_position dw ? ;saved cursor position
video_page db ? ;saved video page number
video_offset dw ? ;starting window offset address
addr_6845 dw ? ;port address of CRTC
ibm db 'IBM' ;EGA ASCII signature
old9h label dword
old9h_vector dw 2 dup (?) ;storage for interrupt 9 vector
;
fill_parms dw 1,030Fh,12
dw 2,050Fh,12
dw 2,070Fh,12
dw 2,090Fh,10
dw 17,0537h,4
dw 0,0737h,4
dw 0,0937h,3
;
def_table db 0,'1234567890-=',0
db 0,'QWERTYUIOP[]',0
db 0,'ASDFGHJKL;',39,96
db 0,0,'ZXCVBNM,./'
db 17 dup (0)
db '789-456+123',0,0
;
scr_table db 0,000,128,129,130,131,132,133,134,135,136,137,138,0
; NOTE 127 ABOVE CHANGED TO 000
db 0,139,140,141,142,143,144,145,146,147,148,149,150,0
db 0,151,152,153,154,155,156,157,158,159,160,161,162
db 0,0,163,164,165,166,167,168,0,0,0,0
db 17 dup (0)
db 201,203,187,205,204,206,185,186,200,202,188,0,0
;
num_table db 0,169,170,171,172,173,174,175,176,177,178,219,220,0
db 0,221,222,223,224,225,226,227,228,229,230,231,232,0
db 0,233,234,235,236,237,238,239,240,241,242,243,244
db 0,0,245,246,247,248,249,250,251,252,253,254
db 17 dup (0)
db 218,194,191,196,195,197,180,179,192,193,217,0,0
;
;------------------------------------------------------------------------------
;Interrupt 9 handler. Execution comes here when a key is pressed or released.
;------------------------------------------------------------------------------
new9h proc near
sti ;set interrupt enable flag
push ax ;save AX
in al,kb_data ;get scan code from keyboard
cmp al,69 ;NumLock key pressed?
je numlock_down ;yes, then branch
cmp al,69+128 ;NumLock key released?
je numlock_up ;yes, then branch
cmp al,70 ;ScrLock key pressed?
je scrlock_down ;yes, then branch
cmp al,70+128 ;ScrLock key released?
je scrlock_up ;yes, then branch
cmp al,57 ;spacebar pressed?
je spacebar ;yes, then branch
cmp aux_shift,0 ;NumLock or ScrLock depressed?
je exit ;no, then exit
jmp newkey ;yes, then branch
exit: pop ax ;restore AX
jmp old9h ;goto old interrupt handler
;
;The NumLock key was pressed. Toggle NumLock state or set shift bit.
;
numlock_down: call get_status ;get main shift status byte
test al,12 ;is either Ctrl or Alt pressed?
jnz exit ;yes, then goto normal handler
push ax ;save shift code
call reset_kb ;reset the keyboard
pop ax ;retrieve shift code
test al,3 ;is either Shift key depressed?
jnz numlock1 ;yes, then branch
or aux_shift,2 ;set NumLock shift bit
jmp end_int ;exit
numlock1: push ds ;save DS
mov ax,bios_data ;point DS to BIOS data area
mov ds,ax
assume ds:bios_data
xor kb_status,32 ;toggle NumLock state
pop ds ;restore DS
assume ds:nothing
jmp end_int ;exit
;
;The NumLock key was released. Clear the NumLock shift bit.
;
numlock_up: call reset_kb ;reset the keyboard
and aux_shift,253 ;clear shift bit
jmp end_int ;exit
;
;The ScrLock key was pressed. Toggle ScrLock state or set shift bit.
;
scrlock_down: call get_status ;get main shift status byte
test al,12 ;is either Ctrl or Alt pressed?
jnz exit ;yes, then goto normal handler
push ax ;save shift code
call reset_kb ;reset the keyboard
pop ax ;retrieve shift code
test al,3 ;is either Shift key depressed?
jnz scrlock1 ;yes, then branch
or aux_shift,1 ;set ScrLock shift bit
jmp end_int ;exit
scrlock1: push ds ;save DS
mov ax,bios_data ;point DS to BIOS data area
mov ds,ax
assume ds:bios_data
xor kb_status,16 ;toggle ScrLock state
pop ds ;restore DS
assume ds:nothing
jmp end_int ;exit
;
;The ScrLock key was released. Clear the ScrLock shift bit.
;
scrlock_up: call reset_kb ;reset the keyboard
and aux_shift,254 ;clear shift bit
end_int: mov al,eoi ;issue EOI to 8259 controller
out int_ctrl,al
pop ax ;clean up the stack
iret ;return from interrupt
;
;The spacebar was pressed. Pop up the window if Alt is depressed.
;
spacebar: call get_status ;get current shift status
test al,8 ;is the Alt key depressed?
jz exit ;no, then exit to normal handler
call reset_kb ;yes, then reset keyboard
mov al,eoi ;issue end-of-interrupt signal
out int_ctrl,al
cmp window_status,0 ;is the window already up?
jne space1 ;yes, then ignore keypress
push bx ;save BX
call kb_display ;pop up keyboard display
pop bx ;restore BX
space1: pop ax ;clean up the stack
iret ;exit
;
;A key was pressed or released with NumLock or ScrLock held down.
;
newkey: push ax ;save scan code
call reset_kb ;reset keyboard
pop ax ;recover scan code
test al,80h ;is the high bit set?
jnz newkey3 ;yes, then don't process it
push bx ;save BX
mov bx,offset num_table ;point BX to NumLock key table
cmp aux_shift,1 ;ScrLock depressed?
jne newkey1 ;no, then continue
mov bx,offset scr_table ;yes, then adjust BX
newkey1: mov ah,al ;transfer scan code to AH
dec al ;set AL relative to zero base
xlat num_table ;get ASCII code from table
or al,al ;is it zero?
je newkey2 ;yes, then don't process this key
call insert_char ;insert character into kb buffer
newkey2: pop bx ;restore BX register value
newkey3: mov al,eoi ;issue end-of-interrupt signal
out int_ctrl,al
pop ax ;restore AX and clean up the stack
iret
new9h endp
;
;------------------------------------------------------------------------------
;RESET_KB resets the keyboard.
;------------------------------------------------------------------------------
reset_kb proc near
in al,kb_ctrl ;get control port value
mov ah,al ;save it
or al,80h ;set high bit of control value
out kb_ctrl,al ;send reset value
mov al,ah ;get original control value
out kb_ctrl,al ;enable keyboard
ret ;done
reset_kb endp
;
;------------------------------------------------------------------------------
;GET_STATUS returns the main keyboard shift status byte in AL.
;------------------------------------------------------------------------------
get_status proc near
push ds ;save DS
mov ax,bios_data ;point DS to BIOS data area
mov ds,ax
assume ds:bios_data
mov al,kb_status ;get status byte in AL
pop ds ;restore DS
assume ds:nothing
ret ;exit
get_status endp
;
;------------------------------------------------------------------------------
;INSERT_CHAR inserts the character code in AX into the keyboard buffer.
;Entry: AH,AL - scan code, ASCII code
;------------------------------------------------------------------------------
insert_char proc near
push dx ;save DX and DS
push ds
mov bx,bios_data ;point DS to BIOS data area
mov ds,bx
assume ds:bios_data
mov bx,buffer_tail ;get current buffer tail address
mov dx,bx ;transfer it to DX
add dx,2 ;calculate next buffer position
cmp dx,buffer_end ;did we overshoot the end?
jne insert1 ;no, then continue
mov dx,buffer_start ;yes, then wrap around
insert1: cmp dx,buffer_head ;is the buffer full?
je insert2 ;yes, then branch
mov [bx],ax ;deposit character into buffer
mov bx,dx ;advance buffer tail
mov buffer_tail,bx ;record its new value
insert2: pop ds ;restore DS
assume ds:nothing
pop dx ;restore DX
ret ;exit
insert_char endp
;
;------------------------------------------------------------------------------
;KB_DISPLAY opens a window showing all possible key definitions.
;------------------------------------------------------------------------------
kb_display proc near
;
;Make sure current video mode is an 80-column text mode.
;
mov ah,15 ;get current video mode
int 10h
cmp al,2 ;video mode 2?
je kb1 ;yes, then continue
cmp al,3 ;video mode 3?
je kb1 ;yes, then continue
cmp al,7 ;video mode 7 (monochrome)?
je kb1
ret ;unsupported mode - terminate
kb1: mov window_status,1 ;set status flag
push cx ;save register values
push dx
push si
push di
push ds
push es
push cs ;set DS and ES to the code segment
pop ds
assume ds:code
push cs
; pop es ;THIS POP MOVED DOWN 3 LINES
;
;Save page number, cursor mode, and cursor position. Then blank the cursor.
;
mov video_page,bh ;store video page number
CALL SET_DISPLAY_TYPE ; CHECK DISPLAY TYPE EACH TIME.
POP ES ; SEE 3 LINES UP
mov ah,3 ;get current cursor mode
int 10h
mov cursor_mode,cx ;store cursor mode
call read_cursor ;get cursor position
mov cursor_position,ax ;save it
mov ah,1 ;hide the cursor
mov ch,20h
int 10h
;
;Save the portion of video memory that will be overwritten.
;
cmp adapter,1 ;disable video if this is a CGA
jne kb2
call disable_cga
kb2: call save_screen ;copy video memory into buffer
;
;Open the keyboard display window.
;
call open_window ;open the window
cmp adapter,1 ;enable CGA video
jne kb3
call enable_cga
kb3: lea si,def_table ;point SI to default key table
call fill_window ;draw unshifted key definitions
;
;The window is open. Loop until the ESC key is pressed, continually monitoring
;the auxiliary shift byte to determine what key definition set to display.
;
kb4: mov ah,1 ;check buffer for character
int 16h
jz kb5 ;branch if buffer is empty
mov ah,0 ;get the character
int 16h
cmp al,27 ;is it the ESC key?
je kb7 ;yes, then close window and exit
kb5: mov al,aux_shift ;get auxiliary shift byte
cmp al,2 ;is it <= 2?
jna kb6 ;yes, then branch
mov al,2 ;no, then set it to 2
kb6: cmp al,old_shift ;has the shift status changed?
je kb4 ;no, then loop back
mov old_shift,al ;record current shift status
mov bl,83 ;calculate table address from AL
mul bl
mov si,ax ;transfer it to SI
add si,offset def_table ;complete offset address in SI
call fill_window ;write key equivalents to window
jmp kb4 ;go back for more
;
;The ESC key was pressed. Close the window and exit.
;
kb7: cmp adapter,1 ;blank CGA video
jne kb8
call disable_cga
kb8: call restore_screen ;restore contents of video memory
cmp adapter,1 ;enable CGA video
jne kb9
call enable_cga
kb9: mov ah,2 ;restore cursor position
mov bh,video_page
mov dx,cursor_position
int 10h
mov ah,1 ;unblank the cursor
mov cx,cursor_mode
int 10h
mov window_status,0 ;reset status flag
pop es ;restore register values
pop ds
pop di
pop si
pop dx
pop cx
ret ;return to calling routine
kb_display endp
;
;------------------------------------------------------------------------------
;SAVE_SCREEN saves the block of video memory that will be overwritten.
;------------------------------------------------------------------------------
save_screen proc near
mov si,182 ;set zero page window offset in SI
mov cl,video_page ;get video page in CX
xor ch,ch
jcxz save2 ;branch if page zero
save1: add si,1000h ;add one page length
loop save1 ;loop until offset is correct
save2: mov video_offset,si ;save starting window address
push ds ;save DS
mov ds,video_segment ;point DS to video memory
assume ds:nothing
mov di,screen_buffer ;point ES:DI to screen buffer
mov cx,11 ;11 lines to save
save3: push cx ;save line counter
mov cx,58 ;58 characters per line
cld ;clear DF
rep movsw ;transfer one line to storage
pop cx ;retrieve counter
add si,44 ;point SI to next line
loop save3 ;loop until all lines are saved
pop ds ;restore DS
assume ds:code
ret
save_screen endp
;
;------------------------------------------------------------------------------
;RESTORE_SCREEN restores saved video memory.
;------------------------------------------------------------------------------
restore_screen proc near
mov es,video_segment ;point ES to video segment
mov di,video_offset ;point DI to window area
mov si,screen_buffer ;point DS:SI to screen buffer
mov cx,11 ;11 lines to restore
restore1: push cx ;save line count
mov cx,58 ;58 characters per line
rep movsw ;restore one line
pop cx ;retrieve count
add di,44 ;advance DI to next line
loop restore1 ;loop until done
ret
restore_screen endp
;
;------------------------------------------------------------------------------
;DISABLE_CGA and ENABLE_CGA control CGA video output.
;------------------------------------------------------------------------------
disable_cga proc near
mov dx,3DAh ;Status Register port address
disable1: in al,dx ;read status
test al,8 ;vertical retrace active?
jz disable1 ;no, then wait until it is
sub dx,2 ;point DX to MSR
mov al,25h ;load disable value
out dx,al ;disable video
ret
disable_cga endp
;
enable_cga proc near
mov ah,15 ;get current video mode
int 10h
lea bx,enable_values ;point BX to table of values
xlat enable_values ;get value to enable signal
mov dx,3D8h ;MSR address
out dx,al ;enable video output
ret
enable_cga endp
;
;------------------------------------------------------------------------------
;READ_CURSOR reads the cursor position directly from the CRT Controller.
;Exit: AH,AL - row, column
;------------------------------------------------------------------------------
read_cursor proc near
mov dx,addr_6845 ;get CRTC Address Register port
mov al,14 ;specify register number
out dx,al
inc dx ;point DX to Data Register
in al,dx ;read high byte of cursor address
mov ah,al ;save it in AH
dec dx ;point DX back to Address Register
mov al,15 ;specify next register number
out dx,al
inc dx ;point DX to Data Register
in al,dx ;read low byte of address
and ax,07FFh ;strip page bits from address
mov bl,80 ;divide by 80
div bl
xchg ah,al ;swap AH and AL
ret
read_cursor endp
;
;------------------------------------------------------------------------------
;OPEN_WINDOW writes the new window to video memory.
;------------------------------------------------------------------------------
open_window proc near
mov es,video_segment ;point ES to video memory
mov di,video_offset ;point DI to start of window
mov al,218 ;get first character code
mov ah,border_attr ;and first attribute byte
stosw ;write
mov cx,56 ;do the next 56 characters
mov al,196
rep stosw
mov al,191 ;finish the first line
stosw
add di,44 ;advance DI to next line
mov cx,9 ;9 identical lines next
open1: push cx ;save line counter
mov al,179 ;do first character
push ax ;save character/attribute
stosw
mov cx,56 ;do the next 56 characters
mov al,32
mov ah,text_attr
rep stosw
pop ax ;retrieve character/attribute pair
stosw ;finish the line
add di,44 ;advance DI to next line
pop cx ;retrieve line count
loop open1 ;loop until all 9 are done
mov al,192 ;first character on last line
stosw
mov cx,56 ;do the next 56
mov al,196
rep stosw
mov al,217 ;finish the last line
stosw
ret
open_window endp
;
;------------------------------------------------------------------------------
;FILL_WINDOW writes a set of key definitions to the open window.
;Entry: DS:SI - key definition table address
;------------------------------------------------------------------------------
fill_window proc near
mov bh,video_page ;retrieve video page number
lea di,fill_parms ;point DI to parameter table
mov cx,7 ;7 lines to write
fill1: push cx ;save counter
add si,word ptr [di] ;adjust table index
mov dx,[di+2] ;set starting cursor position
mov cx,[di+4] ;set number of characters
call writeln ;write one line
add di,6 ;advance parameter table index
pop cx ;retrieve count
loop fill1 ;loop until done
ret
fill_window endp
;
;------------------------------------------------------------------------------
;WRITELN writes one line of key equivalents to the open window.
;Entry: DS:SI - character string address
; BH - video page
; CX - number of characters
; DH,DL - starting row and column
;------------------------------------------------------------------------------
writeln proc near
push cx ;save character counter
mov ah,2 ;position the cursor
int 10h
lodsb ;get one character
mov ah,10 ;print it
mov cx,1
int 10h
add dl,3 ;advance cursor position
pop cx ;retrieve count
loop writeln ;loop until done
ret
writeln endp
;
;------------------------------------------------------------------------------
;INITIALIZE prepares the body of the program for residency.
;------------------------------------------------------------------------------
;
SET_DISPLAY_TYPE PROC NEAR ; CHECKS DISPLAY TYPE FOR WINDOWING EACH TIME
; IT IS USED, NOT JUST AT INITIALIZATION.
;
MOV AH,15
INT 10H
CMP AL,7
JNZ INIT2
MOV ADAPTER,0
MOV VIDEO_SEGMENT,0B000H
MOV BORDER_ATTR,70H
MOV TEXT_ATTR,07H
MOV CURSOR_MODE,0C0DH
JMP INIT3
INIT2: MOV ADAPTER,2
MOV VIDEO_SEGMENT,0B800H
MOV BORDER_ATTR,2FH
MOV TEXT_ATTR,1BH
MOV CURSOR_MODE,0607H
MOV AX,0C000H
MOV ES,AX
MOV DI,1EH
LEA SI,IBM
MOV CX,3
CLD
REPE CMPSB
JZ INIT3
DEC ADAPTER
INIT3: MOV AX,40H
MOV ES,AX
MOV DI,63H
MOV DX,ES:[DI]
MOV ADDR_6845,DX
MOV CX,CURSOR_MODE
MOV AH,1
INT 10H
RET
;
SET_DISPLAY_TYPE ENDP
;
;
;initialize proc near
;
;See if the display adapter is an EGA.
;
; mov ax,0C000h ;set ES to EGA BIOS segment
; mov es,ax
; mov di,1Eh ;point DI to signature location
; lea si,ibm ;point SI to 'IBM' text
; mov cx,3 ;three bytes to compare
; cld ;clear DF
; repe cmpsb ;check three bytes
; je init1 ;branch if signature found
;
;Determine whether adapter is a CGA or an MDA.
;
; dec adapter ;decrement assumed value
; mov ah,15 ;get current video mode
; int 10h
; cmp al,7 ;is it mode 7?
; jne init1 ;no, then it's a CGA
;
;The display adapter is an MDA. Modify video attributes.
;
; dec adapter ;set ADAPTER value for MDA
; sub video_segment, 800h ;modify video segment value
; mov border_attr,70h ;modify border attribute
; mov text_attr,07h ;modify text attribute
; mov cursor_mode,0C0Dh ;modify default cursor shape
;
;Reset the cursor to its default shape.
;
;init1: mov cx,cursor_mode ;set scan lines in CX
; mov ah,1 ;video function - set cursor
; int 10h ;reset cursor
;
;Get and save the address of the CRT Controller.
;
; mov ax,40h ;point ES to BIOS data area
; mov es,ax
; mov di,63h ;point DI to address word
; mov dx,es:[di] ;get CRTC address
; mov addr_6845,dx ;save it
;
INITIALIZE PROC NEAR
;
;Save the old interrupt 9 vector and replace it with a new one.
;
mov ax,3509h ;get current interrupt 9 vector
int 21h
mov old9h_vector,bx ;save it
mov old9h_vector[2],es
mov ah,25h ;then point it to NEW9H routine
lea dx,new9h
int 21h
;
;Terminate, leaving additional room for screen buffering.
;
mov dx,offset initialize+1276 ;set DX for exit
int 27h ;terminate-but-stay-resident
initialize endp
;
code ends
end begin